
var Emitter = cc.Class.extend({

    ctor: function(){
        this.callbacks = {};
    },

    on: function(event,fn) {
        (this.callbacks[event] = this.callbacks[event] || []).push(fn);
        return this;
    },

    once: function(event,fn) {
        var self = this;

        function on() {
            self.off(event,on);
            fn.apply(this,arguments);
        }

        fn._off = on;
        this.on(event,on);
        return this;
    },

    off: function(event,fn){
        return this.removeListener(event,fn);
    },

    removeAllListeners: function(){
        return this.removeListener();
    },

    removeListener: function(event,fn) {

        // all
        if (0 == arguments.length) {
            this.callbacks = {};
            return this;
        }

        // specific event
        var callbacks = this.callbacks[event];
        if (!callbacks) return this;

        // remove all handlers
        if (1 == arguments.length) {
            delete this.callbacks[event];
            return this;
        }

        // remove specific handler
        var i = index(callbacks,fn._off || fn);
        if (~i) callbacks.splice(i,1);
        return this;
    },

    emit: function(event) {
        var args = [].slice.call(arguments,1);
        var callbacks = this.callbacks[event];

        if (callbacks) {
            callbacks = callbacks.slice(0);
            for (var i = 0,len = callbacks.length;i<len;++i) {
                callbacks[i].apply(this,args);
            }
        }

        return this;
    },

    listeners: function(event) {
        return this.callbacks[event] || [];
    },

    hasListeners: function(event) {
        return !! this.listeners(event).length;
    }

});

function index(arr,obj) {
    var indexOf = [].indexOf;
    if (indexOf) return arr.indexOf(obj);
    for (var i = 0;i<arr.length;++i) {
        if (arr[i] === obj) return i;
    }
    return -1;
}
